using System.Net;
using Microsoft.EntityFrameworkCore;
using UniversalAdmin.Domain.Entities;
using File = UniversalAdmin.Domain.Entities.File;

namespace UniversalAdmin.Infrastructure.Data;

public class UniversalAdminDbContext : DbContext
{
    public DbSet<User> Users { get; set; }
    public DbSet<Role> Roles { get; set; }
    public DbSet<Menu> Menus { get; set; }
    public DbSet<UserRole> UserRoles { get; set; }
    public DbSet<RoleMenu> RoleMenus { get; set; }
    public DbSet<OperationLog> OperationLogs { get; set; }
    public DbSet<SystemConfig> SystemConfigs { get; set; }
    public DbSet<File> Files { get; set; }
    public DbSet<RefreshToken> RefreshTokens { get; set; }
    public DbSet<Article> Articles { get; set; }
    public DbSet<ArticleCategory> ArticleCategories { get; set; }

    public UniversalAdminDbContext(DbContextOptions<UniversalAdminDbContext> options) : base(options)
    {
    }

    protected override void OnModelCreating(ModelBuilder modelBuilder)
    {
        base.OnModelCreating(modelBuilder);

        modelBuilder.Entity<UserRole>()
            .HasKey(ur => new { ur.UserId, ur.RoleId });

        modelBuilder.Entity<UserRole>()
            .HasOne(ur => ur.User)
            .WithMany(u => u.UserRoles)
            .HasForeignKey(ur => ur.UserId)
            .OnDelete(DeleteBehavior.Cascade);

        modelBuilder.Entity<UserRole>()
            .HasOne(ur => ur.Role)
            .WithMany(r => r.UserRoles)
            .HasForeignKey(ur => ur.RoleId)
            .OnDelete(DeleteBehavior.Cascade);

        modelBuilder.Entity<RoleMenu>()
            .HasKey(rm => new { rm.RoleId, rm.MenuId });

        modelBuilder.Entity<RoleMenu>()
            .HasOne(rm => rm.Role)
            .WithMany(r => r.RoleMenus)
            .HasForeignKey(rm => rm.RoleId)
            .OnDelete(DeleteBehavior.Cascade);

        modelBuilder.Entity<RoleMenu>()
            .HasOne(rm => rm.Menu)
            .WithMany(m => m.RoleMenus)
            .HasForeignKey(rm => rm.MenuId)
            .OnDelete(DeleteBehavior.Cascade);

        // 配置 OperationLog 和 User 之间的关系
        modelBuilder.Entity<OperationLog>()
            .HasOne(ol => ol.User)
            .WithMany(u => u.OperationLogs)
            .HasForeignKey(ol => ol.UserId)
            .IsRequired(false);

        // 修改 IP 地址的配置
        modelBuilder.Entity<OperationLog>()
            .Property(e => e.IpAddress)
            .HasConversion(
                v => v == null ? null : IPAddress.Parse(v),
                v => v == null ? null : v.ToString())
            .HasColumnType("inet");

        // 配置 RefreshToken 和 User 之间的关系
        modelBuilder.Entity<RefreshToken>()
            .HasOne(rt => rt.User)
            .WithMany(u => u.RefreshTokens)
            .HasForeignKey(rt => rt.UserId)
            .OnDelete(DeleteBehavior.Cascade);

        // 为 RefreshToken 创建索引
        modelBuilder.Entity<RefreshToken>()
            .HasIndex(rt => rt.Token)
            .IsUnique();

        modelBuilder.Entity<RefreshToken>()
            .HasIndex(rt => new { rt.UserId, rt.ExpiresAt });
    }
}